/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ola_device_model.h"

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#include "cJSON.h"
#include "ola_base_utils.h"
#include "ola_def.h"
#include "ola_error.h"
#include "ola_log.h"
#include "ola_pal_os.h"
#include "ola_sdk.h"
#include "ola_security.h"
#include "securec.h"

#define DEV_UDID_BUFF_MAX_LEN 128

static OlaDeviceInfo g_devInfo;
static bool g_devInfoInitFlag = false;

const OlaDeviceInfo *OlaGetDevInfo(void)
{
    if (!g_devInfoInitFlag) {
        OlaLogWarning("devinfo not init");
        return NULL;
    }
    return &g_devInfo;
}

static bool IsDevParamInvalid(const OlaDevParam *devParam)
{
    bool isValid = true;
    isValid = isValid && IsStrInvalid(devParam->sn, OLA_DEV_MODEL_MIN_SN_LEN, OLA_DEV_MODEL_MAX_SN_LEN);
    isValid = isValid && IsStrInvalid(devParam->model, 0, OLA_DEV_MODEL_MAX_MODEL_LEN);
    isValid = isValid && IsStrInvalid(devParam->catID, OLA_DEV_MODEL_CATID_LEN, OLA_DEV_MODEL_CATID_LEN);
    isValid = isValid && IsStrInvalid(devParam->vendorID, OLA_DEV_MODEL_VENDORID_LEN, OLA_DEV_MODEL_VENDORID_LEN);
    isValid = isValid && IsStrInvalid(devParam->devName, 0, OLA_DEV_MODEL_MAX_NAME_LEN);
    isValid = isValid && IsStrInvalid(devParam->prodId, OLA_DEV_MODEL_PRODID_LEN, OLA_DEV_MODEL_PRODID_LEN);
    isValid = isValid && IsStrInvalid(devParam->mac, 0, OLA_DEV_MODEL_MAX_MAC_LEN);
    isValid = isValid && IsStrInvalid(devParam->fwv, 0, OLA_DEV_MODEL_MAX_FWV_LEN);
    isValid = isValid && IsStrInvalid(devParam->hwv, 0, OLA_DEV_MODEL_MAX_HWV_LEN);
    isValid = isValid && IsStrInvalid(devParam->swv, 0, OLA_DEV_MODEL_MAX_SWV_LEN);
    isValid = isValid && IsStrInvalid(devParam->manuName, OLA_DEV_MODEL_MANU_NAME_LEN, OLA_DEV_MODEL_MANU_NAME_LEN);
    isValid =
        isValid && IsStrInvalid(devParam->platformId, OLA_DEV_MODEL_PLATFORM_ID_LEN, OLA_DEV_MODEL_PLATFORM_ID_LEN);
    isValid = isValid && ((devParam->type > 0) && (devParam->type < OLA_PROTOCOL_TYPE_MAX));
    return isValid;
}

static int OlaSetDeviceUdidData(void)
{
    unsigned char udidStr[OLA_UDID_HEX_LEN + 1] = {0}; /* 设备ID字符串 */
    char udidbuf[DEV_UDID_BUFF_MAX_LEN + 1] = {0};

    int udidlen = sprintf_s(udidbuf, sizeof(udidbuf) / sizeof(udidbuf[0]), "%s%s%s", g_devInfo.manuName,
        g_devInfo.model, g_devInfo.sn);
    if (udidlen <= 0) {
        OlaLogError("creat udid data fail");
        return OLA_SECUREC_ERR_SNPRINTF;
    }

    unsigned char udidByteOut[OLA_SHA256_HEX_LEN] = {0};
    int ret = OlaSha256((const unsigned char *)udidbuf, strlen(udidbuf), udidByteOut);
    if (ret != OLA_OK) {
        OlaLogError("Sha256 fail");
        return ret;
    }

    ret = OlaHexify(udidStr, sizeof(udidStr), udidByteOut, OLA_SHA256_HEX_LEN, false);
    if (ret != OLA_OK) {
        OlaLogError("convert fail");
        return ret;
    }
    if ((strcpy_s(g_devInfo.udid, sizeof(g_devInfo.udid), (char *)udidStr) != EOK)) {
        OlaLogError("strcpy failed");
        return OLA_SECUREC_ERR_STRCPY;
    }
    return OLA_OK;
}

static int SetDevInfo(const OlaDevParam *devParam)
{
    (void)memset_s(&g_devInfo, sizeof(OlaDeviceInfo), 0, sizeof(OlaDeviceInfo));
    g_devInfo.protType = devParam->type;
    if ((strcpy_s(g_devInfo.sn, sizeof(g_devInfo.sn), devParam->sn) != EOK) ||
        (strcpy_s(g_devInfo.model, sizeof(g_devInfo.model), devParam->model) != EOK) ||
        (strcpy_s(g_devInfo.catID, sizeof(g_devInfo.catID), devParam->catID) != EOK) ||
        (strcpy_s(g_devInfo.vendorID, sizeof(g_devInfo.vendorID), devParam->vendorID) != EOK) ||
        (strcpy_s(g_devInfo.devName, sizeof(g_devInfo.devName), devParam->devName) != EOK) ||
        (strcpy_s(g_devInfo.prodId, sizeof(g_devInfo.prodId), devParam->prodId) != EOK) ||
        (strcpy_s(g_devInfo.version, sizeof(g_devInfo.version), OLA_VERSION) != EOK) ||
        (strcpy_s(g_devInfo.mac, sizeof(g_devInfo.mac), devParam->mac) != EOK) ||
        (strcpy_s(g_devInfo.fwv, sizeof(g_devInfo.fwv), devParam->fwv) != EOK) ||
        (strcpy_s(g_devInfo.hwv, sizeof(g_devInfo.hwv), devParam->hwv) != EOK) ||
        (strcpy_s(g_devInfo.swv, sizeof(g_devInfo.swv), devParam->swv) != EOK) ||
        (strcpy_s(g_devInfo.manuName, sizeof(g_devInfo.manuName), devParam->manuName) != EOK) ||
        (strcpy_s(g_devInfo.platformId, sizeof(g_devInfo.platformId), devParam->platformId) != EOK)) {
        OlaLogError("strcpy failed");
        return OLA_SECUREC_ERR_STRCPY;
    }
    if (OlaSetDeviceUdidData() != OLA_OK) {
        OlaLogError("set udid failed");
        return OLA_ERROR;
    }
    return OLA_OK;
}

int OlaDevInfoInit(const OlaDevParam *devParam)
{
    if (devParam == NULL || !IsDevParamInvalid(devParam)) {
        OlaLogWarning("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    int ret = SetDevInfo(devParam);
    if (ret != OLA_OK) {
        OlaLogWarning("set dev info error");
        return ret;
    }
    g_devInfoInitFlag = true;
    return OLA_OK;
}